package handler

import (
	"context"
	"godis/cluster"
	"godis/config"
	"godis/database"
	databaseface "godis/interface/database"
	"godis/lib/logger"
	"godis/lib/sync/atomic"
	"godis/resp/connection"
	"godis/resp/parser"
	"godis/resp/reply"
	"io"
	"net"
	"strings"
	"sync"
)

var (
	unknownErrReplyBytes = []byte("-ERR unknown\r\n")
)

type RespHandler struct {
	activeConn sync.Map
	db         databaseface.Database
	closing    atomic.Boolean
}

func MakeHandler() *RespHandler {
	var db databaseface.Database
	//db = database.NewEchoDatabase()
	//db = database.NewStandaloneDatabase()
	if config.Properties.Self != "" && len(config.Properties.Peers) > 0 { // 创建集群
		print("I'm creating ClusterDatabase...\n")
		db = cluster.MakeClusterDatabase()
	} else { // 创建单机版的database
		print("I'm creating StandaloneDatabase...\n")
		db = database.NewStandaloneDatabase()
	}
	return &RespHandler{
		db: db,
	}
}

func (r *RespHandler) closeClient(client *connection.Connection) {
	_ = client.Close()
	r.db.AfterClientClose(client)
	r.activeConn.Delete(client)
}

func (r RespHandler) Handle(ctx context.Context, conn net.Conn) {
	if r.closing.Get() {
		_ = conn.Close()
	}
	client := connection.NewConn(conn)
	r.activeConn.Store(client, struct{}{})

	ch := parser.ParseStream(conn)
	// 只需要监听这个管道即可
	for payload := range ch {
		if payload.Err != nil {
			// 错误的处理逻辑
			if payload.Err == io.EOF ||
				payload.Err == io.ErrUnexpectedEOF ||
				strings.Contains(payload.Err.Error(), "use of closed network connection") {
				r.closeClient(client)
				logger.Info("connection is closed : " + client.RemoteAddr().String())
				return
			}
			// protocol err
			errReply := reply.MakeErrReply(payload.Err.Error())
			err := client.Write(errReply.ToBytes()) // 错误信息回写
			if err != nil {
				r.closeClient(client)
				logger.Info("connection is closed : " + client.RemoteAddr().String())
				return
			}
			continue
		} else {
			// exec
			if payload.Data == nil {
				continue
			}
			reply, ok := payload.Data.(*reply.MultiBulkReply)
			if !ok {
				logger.Error("require multi bulk reply")
				continue
			}
			result := r.db.Exec(client, reply.Args)
			if result != nil {
				_ = client.Write(result.ToBytes())
			} else {
				_ = client.Write(unknownErrReplyBytes)
			}
		}
	}

}

func (r *RespHandler) Close() error {
	logger.Info("handler is shutting down")
	r.closing.Set(true)
	r.activeConn.Range(
		func(key interface{}, value interface{}) bool {
			client := key.(*connection.Connection)
			_ = client.Close()
			return true
		})
	r.db.Close()
	return nil
}
